#pragma once

#include "key/Keyboard_4x4.h"
#include "MotorController.h"
#include "PathController.h"
#include "tim.h"

#pragma region UART Handler

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
}

#pragma endregion

#pragma region Timer Handler

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim == &htim2)
    {
        update_path();
        update_code_wheel_speed();
    }
}

#pragma endregion

#pragma region Code Wheel Handler

/**
 * @brief 中断码盘计数
 * 
 * @param GPIO_Pin 中断脚
 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    switch (GPIO_Pin)
    {
    case Speed_L1_Pin:
        Wheel_L1++;
        Path_L++;
        break;
    case Speed_L2_Pin:
        Wheel_L2++;
        break;
    case Speed_R1_Pin:
        Wheel_R1++;
        Path_R++;
        break;
    case Speed_R2_Pin:
        Wheel_R2++;
        break;
    }
}

#pragma endregion

#pragma region Update Handler

typedef void (*UpdateHandler)();

UpdateHandler updateHandler;

void update_basics()
{
    scan_keyboard(&keyboard, keyHandler);
    HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
    HAL_Delay(200);
}

void update_empty() {}
#pragma endregion

#pragma region Initialize

void init_motor()
{
    L1.IN1.port = Motor_LA1_GPIO_Port;
    L1.IN1.pin = Motor_LA1_Pin;
    L1.IN2.port = Motor_LA2_GPIO_Port;
    L1.IN2.pin = Motor_LA2_Pin;
    L1.pwm.duty = &TIM1->CCR1;
    L1.pwm.maxDuty = MAX_MOTOR_DUTY;
    L1.pid.param = Motor_PIDParam;

    L2.IN1.port = Motor_LB1_GPIO_Port;
    L2.IN1.pin = Motor_LB1_Pin;
    L2.IN2.port = Motor_LB2_GPIO_Port;
    L2.IN2.pin = Motor_LB2_Pin;
    L2.pwm.duty = &TIM1->CCR2;
    L2.pwm.maxDuty = MAX_MOTOR_DUTY;
    L2.pid.param = Motor_PIDParam;

    R1.IN1.port = Motor_RA1_GPIO_Port;
    R1.IN1.pin = Motor_RA1_Pin;
    R1.IN2.port = Motor_RA2_GPIO_Port;
    R1.IN2.pin = Motor_RA2_Pin;
    R1.pwm.duty = &TIM1->CCR3;
    R1.pwm.maxDuty = MAX_MOTOR_DUTY;
    R1.pid.param = Motor_PIDParam;

    R2.IN1.port = Motor_RB1_GPIO_Port;
    R2.IN1.pin = Motor_RB1_Pin;
    R2.IN2.port = Motor_RB2_GPIO_Port;
    R2.IN2.pin = Motor_RB2_Pin;
    R2.pwm.duty = &TIM1->CCR4;
    R2.pwm.maxDuty = MAX_MOTOR_DUTY;
    R2.pid.param = Motor_PIDParam;

    //启动PWM
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4);
    //启动码盘更新定时器
    HAL_TIM_Base_Start_IT(&htim2);
}

void init_basics()
{
    /* initialize EasyLogger */
    elog_init();
    /* set EasyLogger log format */
    elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);
    elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG);
    elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG);
    elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG);
    elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_LVL | ELOG_FMT_TAG);
    elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_LVL | ELOG_FMT_TAG);
    /* start EasyLogger */
    elog_start();

    log_i("Initialing Keyboard!");
    keyboard_init();

    log_i("Setting up GuideNodes!");
    setup_nodes();

    log_i("Initialing Motor!");
    init_motor();

    updateHandler = update_basics;

    log_i("Initialize completed!");
}

#pragma endregion